# coding: utf-8
import httplib
import logging
import logging.handlers

import settings
import elements
import utils
from dav_exceptions import *

log = logging.getLogger('client')
log.setLevel(level=settings.LOG_LEVEL)
handler = logging.handlers.RotatingFileHandler(settings.LOG_FILE, maxBytes=settings.LOG_FILE_SIZE)
handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
log.addHandler(handler)

def get(credentials, path):
    headers = {'User-Agent':'Boxlet', 'Expect':'307-Temporary Redirect'}
    if credentials:
        headers.update({'Authorization':credentials})
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    httpconn.request('GET', path, '', headers)
    response = httpconn.getresponse()
    body = response.read()
    if response.status == 307:
        location = response.getheader('Location')
        location = 'http://%s:%s%s' % (settings.server, settings.port, location)
        log.info('GET url %s for %s from EaseDAV' % (location, path))
        return location
    elif response.status == 403:
        log.info('GET %s failed since privilege needed.')
        log.debug(body)
        raise NeedPrivileges
    elif response.status == 404:
        raise NotFound
    else:
        log.error('GET %s error.' % path)
        log.error(body)
        raise Exception

def propfind(credentials, path, properties, depth=1):
    if not path:
        return []
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
    pf = elements.DAVPropfind(prop=elements.DAVProp())
    for p in properties:
        pf.prop[p] = elements.DAVElementFactory.CreateByTag(*utils.separate_ns_ln(p))
    body = pf.dumpXML()
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    headers['Depth'] = str(depth)
    httpconn.request('PROPFIND', path, body, headers)
    response = httpconn.getresponse()
    body = response.read()
    httpconn.close()
    if response.status == 207:
        multistatus = elements.DAVMultistatus()
        multistatus.loadXML(body)
        log.info('PROPFIND %s' % path)
        log.debug(body)
        return multistatus
    elif response.status == 403:
        raise NeedPrivileges
    elif response.status == 404:
        raise NotFound
    else:
        log.error('PROPFIND %s error.' % path)
        log.error(body)
        raise Exception

def propertyupdate(credentials, path,
                   set_names=None, set_values=None,
                   remove_names=None, remove_values=None):
    '''
    Parameters:
        `path':
        `set_name': 
    '''
    pu = elements.DAVPropertyupdate()
    if set_names and set_values:
        for name, value in zip(set_names, set_values):
            oneset = elements.DAVSet(prop=elements.DAVProp())
            oneset.prop[name] = elements.DAVElementFactory.CreateByXML(value)
            pu.setList.append(oneset)
    if remove_names and remove_values:
        for name, value in zip(remove_names, remove_values):
            oneremove = elements.DAVRemove(prop=elements.DAVProp())
            oneremove.prop[name] = elements.DAVElementFactory.CreateByTag(*utils.separate_ns_ln(name))
            pu.removeList.append(oneremove)
            
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
        
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    httpconn.request('PROPPATCH', path, pu.dumpXML(), headers)
    response = httpconn.getresponse()
    body = response.read()
    httpconn.close()
    
    if response.status == 207:
        multistatus = elements.DAVMultistatus()
        multistatus.loadXML(body)
        log.info('PROPERTYUPDATE %s' % path)
        log.debug(body)
        return multistatus.responseList
    elif response.status == 403:
        raise NeedPrivileges
    elif response.status == 404:
        raise NotFound
    else:
        log.error('Property update %s error.' % path)
        log.error('%s' % body)

def put(credentials, path, data):
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    httpconn.request('PUT', path, data, headers)
    response = httpconn.getresponse()
    body = response.read()
    httpconn.close()
    log.info('PUT %s' % path)
    log.debug(body)
    if response.status == 201:
        return True
    elif response.status == 403:
        raise NeedPrivileges
    else:
        log.error('PUT %s error.' % path)
        log.error('Response: %s - %s - %s' % (response.status, response.response, body))

def delete(credentials, path):
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
    headers['Destination'] = path
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    httpconn.request('DELETE', path, '', headers)
    response = httpconn.getresponse()
    body = response.read()
    httpconn.close()
    if response.status == 204:
        log.debug('DELETE %s' % path)
        return True
    elif response.status == 403:
        raise NeedPrivileges
    elif response.status == 404:
        raise NotFound
    else:
        log.error('DELETE %s error.' % path)
        log.error('Response: %s - %s - %s' % (response.status, response.response, body))

def mkcol(credentials, path):
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    httpconn.request('MKCOL', path, '', headers)
    response = httpconn.getresponse()
    body = response.read()
    httpconn.close()
    return response.status

def copy(src, dst):
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
    return True

def move(credentials, src, dst):
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    headers['Destination'] = dst
    httpconn.request('MOVE', src, '', headers)
    response = httpconn.getresponse()
    data = response.read()
    httpconn.close()
    return response.status

def grant(credentials, path, principal, privilege, isgrant):
    headers = {'User-Agent':'Boxlet'}
    if credentials:
        headers.update({'Authorization':credentials})
    if isgrant:
        acl = '<acl xmlns="DAV:"><ace>%s<grant><privilege>%s</privilege></grant></ace></acl>' % (principal, privilege)
    else:
        acl = '<acl xmlns="DAV:"><ace>%s<deny><privilege>%s</privilege></deny></ace></acl>' % (principal, privilege)
        
    log.info('%s %s' % (isgrant and 'GRANT' or 'DENY', path))
    log.debug(acl)
    
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    httpconn.request('ACL', path, acl, headers)
    httpconn.send(acl)
    response = httpconn.getresponse()
    body = response.read()
    httpconn.close()
    
    if response.status == 200:
        return True
    elif response.status == 403:
        raise NeedPrivileges
    elif response.status == 404:
        raise NotFound
    else:
        log.error('GRANT %s error.' % path)
        log.error('%s' % body)

def report(credentials, path, body, depth='0'):
    headers = {'User-Agent':'Boxlet', 'Depth':depth}
    if credentials:
        headers.update({'Authorization':credentials})
    log.info('REPORT - %s' % path)
    log.debug(body)
    
    httpconn = httplib.HTTPConnection(settings.server, port=settings.port)
    httpconn.request('REPORT', path, body, headers)
    httpconn.send(body)
    response = httpconn.getresponse()
    body = response.read()
    httpconn.close()

    if response.status == 207:
        multistatus = elements.DAVMultistatus()
        multistatus.loadXML(body)
        return multistatus
    elif response.status == 403:
        raise NeedPrivileges
    elif response.status == 404:
        raise NotFound
    else:
        log.error('REPORT %s error.' % path)
        log.error('Response: %s - %s - %s' % (response.status, response.response, body))
    

def principal_property_search(credentials, path, kvset, props, depth='0'):
    pps = elements.DAVPrincipal_property_search(prop=elements.DAVProp())
    for k, v in kvset:
        ps = elements.DAVProperty_search(prop=elements.DAVProp(), match=elements.DAVMatch(match=v))
        ps.prop[k] = elements.DAVElementFactory.CreateByTag(*utils.separate_ns_ln(k))
        pps.property_searchList.append(ps)
    for prop in props:
        pps.prop[prop] = elements.DAVElementFactory.CreateByTag(*utils.separate_ns_ln(prop))
    return report(credentials, path, pps.dumpXML(), depth)

def principal_match(credentials, path, principal_property, props, depth='0'):
    pm = elements.DAVPrincipal_match(
        principal_property=elements.DAVPrincipal_property(),
        prop=elements.DAVProp())
    pm.principal_property[principal_property] = elements.DAVElementFactory.CreateByTag(*utils.separate_ns_ln(principal_property))
    for prop in props:
        pm.prop[prop] = elements.DAVElementFactory.CreateByTag(*utils.separate_ns_ln(prop))
    return report(credentials, path, pm.dumpXML(), depth)
